﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Serialization.Formatters;
using System.Collections;
using System.Threading;

namespace Soft.Net
{


    /// <summary>
    /// 网络管理类
    /// </summary>
    public static class NetManager
    {

        /// <summary>
        /// 服务端TcpChannel
        /// </summary>
        public static TcpServerChannel TcpServerChannel { get; private set; }


        /// <summary>
        /// 客户端TcpChannel
        /// </summary>
        public static TcpClientChannel  TcpClientChannel { get; private set; }


        /// <summary>
        /// 本地IP地址
        /// </summary>
        public static string LocalHostIpsDescribe { get; private set; } = string.Join<IPAddress>(",", from e in Dns.GetHostAddresses(Dns.GetHostName())
                                                                                                      where e.AddressFamily == AddressFamily.InterNetwork
                                                                                                      select e);


        /// <summary>
        /// 注册TcpChannel通道
        /// </summary>
        /// <param name="channelName">通道的名册</param>
        /// <param name="port">端口号</param>
        /// <returns></returns>
        public static Result RegisterTcpChannel(string channelName, ushort? port = null)
        {
            Result result = new Result();
            List<IChannel> list = new List<IChannel>(ChannelServices.RegisteredChannels);
            if (!list.Exists((IChannel c) => c.ChannelName == channelName))
            {
                try
                {
                    IDictionary dictionary = new Hashtable();
                    dictionary["name"] = channelName;
                    if (port != null)
                    {
                        dictionary["port"] = port;
                    }
                    IChannel channel = new TcpChannel(dictionary, new BinaryClientFormatterSinkProvider(), new BinaryServerFormatterSinkProvider
                    {
                        TypeFilterLevel = TypeFilterLevel.Full,
                        Next = new ClientIPServerSinkProvider()
                    });
                    ChannelServices.RegisterChannel(channel, false);
                }
                catch (Exception exception)
                {
                    result.AddError(exception, null);
                }
            }
            return result;
        }


        /// <summary>
        /// 注册服务类型
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static Result RegisterServiceType<T>() where T : BaseRemotingObject
        {
            Result result;
            try
            {
                Type serviceType = typeof(T);
                if (!RemotingConfiguration.GetRegisteredWellKnownServiceTypes().Any((WellKnownServiceTypeEntry e) => e.ObjectType == serviceType))
                {
                    //每次调用实例化一个ServiceType
                    RemotingConfiguration.RegisterWellKnownServiceType(serviceType, serviceType.FullName, WellKnownObjectMode.SingleCall);
                }
                result = new Result();
            }
            catch (Exception e)
            {
                result = new Result(e, null);
            }
            return result;
        }


        /// <summary>
        /// 获取远程对象（使用Activator激活对象T的实例）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="address"></param>
        /// <returns></returns>
        public static ResultData<T> GetObjectFromRemote<T>(TcpConnectIpAddress address) where T : BaseRemotingObject
        {
            ResultData<T> resultData = new ResultData<T>();
            if (address == TcpConnectIpAddress.Empty)
            {
                resultData.AddError("远程地址不能是：" + TcpConnectIpAddress.Empty.ToString(), null);
            }
            if (resultData.Succeed)
            {
                try
                {
                    resultData.Data = (T)((object)Activator.GetObject(typeof(T), NetManager.BuildingUri(address.IpAddress, address.Port, typeof(T))));
                }
                catch (Exception exception)
                {
                    resultData.AddError(exception, null);
                }
            }
            return resultData;
        }


        /// <summary>
        /// 注册服务端通道  TcpServerChannel
        /// </summary>
        /// <param name="channelName"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public static Result RegisterTcpServerChannel(string channelName, ushort port)
        {
            Result result = new Result();
            List<IChannel> list = new List<IChannel>(ChannelServices.RegisteredChannels);
            if (!list.Exists((IChannel c) => c.ChannelName == channelName))
            {
                try
                {
                    Hashtable hashtable = new Hashtable();
                    hashtable.Add("name", channelName);
                    hashtable.Add("port", port);
                    hashtable.Add("timeout", NetManager.RemotingTimeOutSecond * 1000);
                    ClientIPServerSinkProvider next = new ClientIPServerSinkProvider();
                    NetManager.TcpServerChannel = new TcpServerChannel(hashtable, new BinaryServerFormatterSinkProvider
                    {
                        TypeFilterLevel = TypeFilterLevel.Full,
                        Next = next
                    });
                    ChannelServices.RegisterChannel(NetManager.TcpServerChannel, false);
                }
                catch (Exception exception)
                {
                    result.AddError(exception, null);
                }
            }
            return result;
        }


        /// <summary>
        /// 注销所有的通道
        /// </summary>
        /// <returns></returns>
        public static Result UnregisterAllChannels()
        {
            Result result = new Result();
            foreach (IChannel chnl in ChannelServices.RegisteredChannels)
            {
                try
                {
                    ChannelServices.UnregisterChannel(chnl);
                }
                catch (Exception exception)
                {
                    result.AddError(exception, null);
                }
            }
            return result;
        }


        /// <summary>
        /// 注销所有的服务通道
        /// </summary>
        /// <returns></returns>
        public static Result UnregisterTcpServerChannel()
        {
            Result result = new Result();
            try
            {
                if (NetManager.TcpServerChannel != null)
                {
                    ChannelServices.UnregisterChannel(NetManager.TcpServerChannel);
                }
            }
            catch (Exception exception)
            {
                result.AddError(exception, null);
            }
            return result;
        }


        /// <summary>
        /// 注册客户端通道
        /// </summary>
        /// <returns></returns>
        public static Result RegisterTcpClientChannel()
        {
            Result result = new Result();
            int num = 0;
            for (; ; )
            {
                List<IChannel> list = new List<IChannel>(ChannelServices.RegisteredChannels);
                if (!list.Exists((IChannel c) => c.ChannelName == NetManager.ClientChannelName))
                {
                    try
                    {
                        BinaryClientFormatterSinkProvider sinkProvider = new BinaryClientFormatterSinkProvider();
                        NetManager.TcpClientChannel = new TcpClientChannel(new Hashtable
                        {
                            {
                                "name",
                                NetManager.ClientChannelName
                            },
                            {
                                "timeout",
                                NetManager.RemotingTimeOutSecond * 1000
                            }
                        }, sinkProvider);
                        ChannelServices.RegisterChannel(NetManager.TcpClientChannel, false);
                    }
                    catch (RemotingException exception)
                    {
                        if (++num <= 2)
                        {
                            Thread.Sleep(200);
                            continue;
                        }
                        result.AddError(exception, null);
                    }
                    catch (Exception exception2)
                    {
                        result.AddError(exception2, null);
                    }
                    break;
                }
                break;
            }
            return result;
        }


        /// <summary>
        /// 注销客户端通道
        /// </summary>
        /// <returns></returns>
        public static Result UnregisterTcpClientChannel()
        {
            Result result = new Result();
            try
            {
                if (NetManager.TcpClientChannel != null)
                {
                    ChannelServices.UnregisterChannel(NetManager.TcpClientChannel);
                }
            }
            catch (Exception exception)
            {
                result.AddError(exception, null);
            }
            return result;
        }


        /// <summary>
        /// 将远程对象转换为ObjRef 对象的引用
        /// </summary>
        /// <param name="remotingObject"></param>
        /// <returns></returns>
        public static ResultData<ObjRef> RegisterServiceObject(BaseRemotingObject remotingObject)
        {
            ResultData<ObjRef> resultData = new ResultData<ObjRef>();
            if (remotingObject == null)
            {
                resultData.AddError(new ArgumentNullException("remotingObject"), null);
            }
            if (resultData.Succeed)
            {
                try
                {
                    resultData.Data = RemotingServices.Marshal(remotingObject, remotingObject.GetType().FullName);
                }
                catch (Exception exception)
                {
                    resultData.AddError(exception, null);
                }
            }
            return resultData;
        }


        /// <summary>
        /// 注销远程对象的 引用 
        /// </summary>
        /// <param name="objRef"></param>
        /// <returns></returns>
        public static Result UnregisterServiceObject(ObjRef objRef)
        {
            Result result = new Result();
            try
            {
                RemotingServices.Unmarshal(objRef);
            }
            catch (Exception exception)
            {
                result.AddError(exception, null);
            }
            return result;
        }


        /// <summary>
        /// 通过IP地址 获取远程对象 Activator模式
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="address"></param>
        /// <returns></returns>
        public static ResultData<T> GetRemotingObject<T>(TcpConnectIpAddress address) where T : BaseRemotingObject
        {
            ResultData<T> resultData = new ResultData<T>();
            if (address == TcpConnectIpAddress.Empty)
            {
                resultData.AddError("远程地址不能是：" + TcpConnectIpAddress.Empty.ToString(), null);
            }
            if (resultData.Succeed)
            {
                try
                {
                    resultData.Data = (T)((object)Activator.GetObject(typeof(T), NetManager.BuildingUri(address.IpAddress, address.Port, typeof(T))));
                }
                catch (Exception exception)
                {
                    resultData.AddError(exception, null);
                }
            }
            return resultData;
        }


        /// <summary>
        /// 通过IP地址  获取远程对象  通过Activator模式
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public static ResultData<T> GetRemotingObject<T>(IP ip, ushort port) where T : BaseRemotingObject
        {
            ResultData<T> resultData = new ResultData<T>();
            if (ip == IP.Empty)
            {
                resultData.AddError("远程地址不能是：" + IP.Empty.ToString(), null);
            }
            if (resultData.Succeed)
            {
                try
                {
                    resultData.Data = (T)((object)Activator.GetObject(typeof(T), NetManager.BuildingUri(ip, port, typeof(T))));
                }
                catch (Exception exception)
                {
                    resultData.AddError(exception, null);
                }
            }
            return resultData;
        }


        /// <summary>
        ///  通过IP 端口和远程对象的类型  返回可以使用TCP访问对象 的Uri 
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <param name="remoteObjectType"></param>
        /// <returns></returns>
        public static string BuildingUri(IP ip, ushort port, Type remoteObjectType)
        {
            return string.Concat(new string[]
            {
                "tcp://",
                ip.ToString(),
                ":",
                port.ToString(),
                "/",
                remoteObjectType.FullName
            });
        }


       /// <summary>
       /// jobServer 通道名称
       /// </summary>
        public static readonly string JobServerChannelName = "SoftTcpJobServiceChannel";


        /// <summary>
        /// MpapingService 通道名称
        /// </summary>
        public static readonly string MappingServiceChannelName = "SoftTcpMappingServiceChannel";


        /// <summary>
        /// 更新服务通道 名称
        /// </summary>
        public static readonly string UpdateServiceChannelName = "SoftTcpUpdateServiceChannel";


        /// <summary>
        /// 客户端通道名称
        /// </summary>
        public static readonly string ClientChannelName = "SoftTcpClientChannel";


        /// <summary>
        /// 更新客户端通道名称
        /// </summary>
        public static readonly string UpdateClientChannelName = "SoftTcpUpdateClientChannel";


        /// <summary>
        /// jobService 端口号
        /// </summary>
        public static readonly ushort JobServicePort = 7608;


        /// <summary>
        /// Mapping 端口号
        /// </summary>
        public static readonly ushort MappingPort = 1708;


        /// <summary>
        /// JobServce 在线接收udp报文端口
        /// </summary>
        public static readonly int JobServiceOnlineUDPPort = 7115;


        /// <summary>
        /// 更新控制服务端口
        /// </summary>
        public static readonly ushort UpdateControlServicePost = 6663;


        /// <summary>
        /// 远程超时时间  30s
        /// </summary>
        public static int RemotingTimeOutSecond = 30;


    }
}
